package mynl

import (
	"fmt"
	"strconv"
	"strings"
)

////////////////////////////////////////////////////////////////////////////////
//Parser
/**
 * 基类，标识AST的一个节点
 */
type IAstNode interface {
	//打印对象信息，prefix是前面填充的字符串，通常用于缩进显示
	Dump(prefix string)

	//visitor模式中，用于接受vistor的访问。
	Accept(visitor *IAstVisitor) interface{}
}

/**
 * 声明
 * 所有声明都会对应一个符号。
 */
type Decl struct {
	Name string
}

func NewDecl(name string) *Decl {
	return &Decl{
		Name: name,
	}
}

/**
 * 函数声明节点
 */
type FunctionDecl struct {
	IStatement
	Decl
	Body Block //函数体
}

func NewFunctionDecl(name string, body Block) *FunctionDecl {
	return &FunctionDecl{
		Decl: *NewDecl(name),
		Body: body,
	}
}

func (selfx *FunctionDecl) getStatementType() string {
	return "FunctionDecl"
}

func (selfx *FunctionDecl) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitFunctionDecl(visitor, selfx)
}

func (selfx *FunctionDecl) Dump(prefix string) {
	fmt.Println(prefix + "FunctionDecl " + selfx.Name)
	selfx.Body.Dump(prefix + "    ")
}

/**
 * 函数体
 */
type Block struct {
	IAstNode
	Stmts []IStatement
}

func NewBlock(stmts []IStatement) *Block {
	return &Block{
		Stmts: stmts,
	}
}

func (selfx *Block) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitBlock(visitor, selfx)
}

func (selfx *Block) Dump(prefix string) {
	fmt.Println(prefix + "Block")

	for _, stmt := range selfx.Stmts {
		stmt.Dump(prefix + "\t")
	}
}

/**
 * 程序节点，也是AST的根节点
 */
type Prog struct {
	Block
}

func NewProg(stmts []IStatement) *Prog {
	return &Prog{
		Block: *NewBlock(stmts),
	}
}

func (selfx *Prog) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitProg(visitor, selfx)
}

func (selfx *Prog) Dump(prefix string) {
	fmt.Println(prefix + "Prog")
	for _, stmt := range selfx.Stmts {
		stmt.Dump(prefix + "\t")
	}
}

/**
 * 变量声明节点
 */
type VariableDecl struct {
	IStatement
	Decl
	varType string       //变量类型
	init    *IExpression //变量初始化所使用的表达式
}

func NewVariableDecl(name string, varType string, init *IExpression) *VariableDecl {
	return &VariableDecl{
		Decl:    *NewDecl(name),
		varType: varType,
		init:    init,
	}
}

func (selfx *VariableDecl) getStatementType() string {
	return "VariableDecl"
}

func (selfx *VariableDecl) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitVariableDecl(visitor, selfx)
}

func (selfx *VariableDecl) Dump(prefix string) {
	fmt.Println(prefix + "VariableDecl " + selfx.Name + ", type: " + selfx.varType)
	if selfx.init == nil {
		fmt.Println(prefix + "no initialization.")
	} else {
		(*selfx.init).Dump(prefix + "    ")
	}
}

/**
 * 语句
 * 其子类包括函数声明、表达式语句
 */
type IStatement interface {
	IAstNode
	getStatementType() string
}

/**
 * 语句
 * 其子类包括函数声明、表达式语句
 */
type IExpression interface {
	IAstNode
	getExpressionType() string
}

/**
 * 二元表达式
 */
type BinaryOP struct {
	IExpression
	op   string      //运算符
	exp1 IExpression //左边的表达式
	exp2 IExpression //右边的表达式
}

func NewBinaryOP(op string, exp1 IExpression, exp2 IExpression) *BinaryOP {
	return &BinaryOP{
		op:   op,
		exp1: exp1,
		exp2: exp2,
	}
}

func (selfx *BinaryOP) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitBinaryOP(visitor, selfx)
}

func (selfx *BinaryOP) Dump(prefix string) {
	fmt.Println(prefix + "Binary:" + selfx.op)
	selfx.exp1.Dump(prefix + "    ")
	selfx.exp2.Dump(prefix + "    ")
}

/**
 * 表达式语句
 * 就是在表达式后面加个分号
 */
type ExpressionStatement struct {
	IAstNode
	IStatement
	exp IExpression
}

func NewExpressionStatement(exp IExpression) *ExpressionStatement {
	return &ExpressionStatement{
		exp: exp,
	}
}

func (selfx *ExpressionStatement) getStatementType() string {
	return "ExpressionStatement"
}

func (selfx *ExpressionStatement) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitExpressionStatement(visitor, selfx)
}

func (selfx *ExpressionStatement) Dump(prefix string) {
	fmt.Println(prefix + "ExpressionStatement")
	selfx.exp.Dump(prefix + "    ")
}

/**
 * 函数调用节点
 */
type FunctionCall struct {
	IAstNode
	IExpression
	Name       string
	Parameters []IExpression
	FuncDecl   *FunctionDecl //指向函数的声明
}

func NewFunctionCall(name string, parameters []IExpression) *FunctionCall {
	return &FunctionCall{
		Name:       name,
		Parameters: parameters,
	}
}

func (selfx *FunctionCall) getExpressionType() string {
	return "FunctionCall"
}

func (selfx *FunctionCall) Accept(visitor *IAstVisitor) interface{} {
	// fmt.Println(reflect.TypeOf(visitor))
	return (*visitor).visitFunctionCall(visitor, selfx)
}

func (selfx *FunctionCall) Dump(prefix string) {
	if strings.HasPrefix(selfx.Name, "nl.") {
		fmt.Println(prefix, "SysCall ", selfx.Name, ", resolved")
	} else {
		fmt.Println(prefix, "FunctionCall ", selfx.Name, IF(selfx.FuncDecl != nil, ", resolved", ", not resolved"))
	}

	for _, p := range selfx.Parameters {
		p.Dump(prefix + "\t")
	}
}

/**
 * 变量引用
 */
type Variable struct {
	IExpression
	IAstNode
	Name    string
	VarDecl *VariableDecl //指向变量声明
}

func NewVariable(name string) *Variable {
	return &Variable{
		Name: name,
	}
}

func (selfx *Variable) getExpressionType() string {
	return "Variable"
}

func (selfx *Variable) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitVariable(visitor, selfx)
}

func (selfx *Variable) Dump(prefix string) {
	if strings.HasPrefix(selfx.Name, "nl.") {
		fmt.Println(prefix, "SysCall ", selfx.Name, ", resolved")
	} else {
		fmt.Println(prefix, "Variable: ", selfx.Name, IF(selfx.VarDecl != nil, ", resolved", ", not resolved"))
	}
}

/**
 * 字符串字面量
 */
type StringLiteral struct {
	IExpression
	IAstNode
	value string
}

func NewStringLiteral(value string) *StringLiteral {
	return &StringLiteral{
		value: value,
	}
}

func (selfx *StringLiteral) getExpressionType() string {
	return "StringLiteral"
}

func (selfx *StringLiteral) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitStringLiteral(visitor, selfx)
}

func (selfx *StringLiteral) Dump(prefix string) {
	fmt.Println(prefix + selfx.value)
}

/**
 * 整型字面量
 */
type IntegerLiteral struct {
	IExpression
	IAstNode
	value int
}

func NewIntegerLiteral(str string) *IntegerLiteral {
	var value, err = strconv.Atoi(str)
	if err != nil {
		return nil
	}

	return &IntegerLiteral{
		value: value,
	}
}

func (selfx *IntegerLiteral) getExpressionType() string {
	return "IntegerLiteral"
}

func (selfx *IntegerLiteral) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitIntegerLiteral(visitor, selfx)
}

func (selfx *IntegerLiteral) Dump(prefix string) {
	fmt.Println(prefix, selfx.value)
}

/**
 * 实数字面量
 */
type DecimalLiteral struct {
	IExpression
	IAstNode
	value float64
}

func NewDecimalLiteral(str string) *DecimalLiteral {
	var value, err = strconv.ParseFloat(str, 64)
	if err != nil {
		return nil
	}

	return &DecimalLiteral{
		value: value,
	}
}

func (selfx *DecimalLiteral) getExpressionType() string {
	return "DecimalLiteral"
}

func (selfx *DecimalLiteral) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitDecimalLiteral(visitor, selfx)
}

func (selfx *DecimalLiteral) Dump(prefix string) {
	fmt.Println(prefix, selfx.value)
}

/**
 * null字面量
 */
type NullLiteral struct {
	IExpression
	IAstNode
	value interface{}
}

func NewNullLiteral() *NullLiteral {
	return &NullLiteral{}
}

func (selfx *NullLiteral) getExpressionType() string {
	return "NullLiteral"
}

func (selfx *NullLiteral) Accept(visitor *IAstVisitor) interface{} {
	return (*visitor).visitNullLiteral(visitor, selfx)
}

func (selfx *NullLiteral) Dump(prefix string) {
	fmt.Println(prefix, selfx.value)
}

/**
 * Boolean字面量
 */
type BooleanLiteral struct {
	IExpression
	IAstNode
	value bool
}

func NewBooleanLiteral(value bool) *BooleanLiteral {
	return &BooleanLiteral{
		value: value,
	}
}

func (selfx *BooleanLiteral) getExpressionType() string {
	return "BooleanLiteral"
}

func (selfx *BooleanLiteral) Accept(visitor *IAstVisitor) bool {
	return (*visitor).visitBooleanLiteral(visitor, selfx)
}

func (selfx *BooleanLiteral) Dump(prefix string) {
	fmt.Println(prefix, selfx.value)
}

////////////////////////////////////////////////////////////////////////////////
//Visitor

type IAstVisitor interface {
	visitProg(caller *IAstVisitor, prog *Prog) interface{}
	visitVariableDecl(caller *IAstVisitor, variableDecl *VariableDecl) interface{}
	visitFunctionDecl(caller *IAstVisitor, functionDecl *FunctionDecl) interface{}
	visitBlock(caller *IAstVisitor, block *Block) interface{}
	visitExpressionStatement(caller *IAstVisitor, stmt *ExpressionStatement) interface{}
	visitBinaryOP(caller *IAstVisitor, exp *BinaryOP) interface{}
	visitIntegerLiteral(caller *IAstVisitor, exp *IntegerLiteral) int
	visitDecimalLiteral(caller *IAstVisitor, exp *DecimalLiteral) float64
	visitStringLiteral(caller *IAstVisitor, exp *StringLiteral) string
	visitNullLiteral(caller *IAstVisitor, exp *NullLiteral) interface{}
	visitBooleanLiteral(caller *IAstVisitor, exp *BooleanLiteral) bool
	visitVariable(caller *IAstVisitor, variable *Variable) interface{}
	visitFunctionCall(caller *IAstVisitor, functionCall *FunctionCall) interface{}
}

/**
 * 对AST做遍历的Vistor。
 * 这是一个基类，定义了缺省的遍历方式。子类可以覆盖某些方法，修改遍历方式。
 */
type AstVisitor struct {
}

//对抽象类的访问。
//相应的具体类，会调用visitor合适的具体方法。
func (selfx *AstVisitor) Visit(caller *IAstVisitor, node *IAstNode) interface{} {
	return (*node).Accept(caller)
}

func (selfx AstVisitor) visitProg(caller *IAstVisitor, prog *Prog) interface{} {
	var retVal interface{}
	for i := range prog.Stmts {
		var node IAstNode = prog.Stmts[i]
		retVal = selfx.Visit(caller, &node)
	}

	return retVal
}

func (selfx AstVisitor) visitVariableDecl(caller *IAstVisitor, variableDecl *VariableDecl) interface{} {
	if variableDecl.init != nil {
		var node IAstNode = *(variableDecl.init)
		return selfx.Visit(caller, &node)
	}

	return nil
}

//通过函数声明，访问Block
//这里要看子类如何继承
func (selfx AstVisitor) visitFunctionDecl(caller *IAstVisitor, functionDecl *FunctionDecl) interface{} {
	return selfx.visitBlock(caller, &functionDecl.Body)
}

//Block中，依次执行每个语句
func (selfx AstVisitor) visitBlock(caller *IAstVisitor, block *Block) interface{} {
	var retVal interface{}
	for i := range block.Stmts {
		var node IAstNode = block.Stmts[i]
		retVal = selfx.Visit(caller, &node)
	}

	return retVal
}

func (selfx AstVisitor) visitExpressionStatement(caller *IAstVisitor, stmt *ExpressionStatement) interface{} {
	var node1 IAstNode = stmt.exp
	return selfx.Visit(caller, &node1)
}

func (selfx AstVisitor) visitBinaryOP(caller *IAstVisitor, exp *BinaryOP) interface{} {
	var node1 IAstNode = exp.exp1
	var node2 IAstNode = exp.exp2
	selfx.Visit(caller, &node1)
	selfx.Visit(caller, &node2)
	return nil
}

func (selfx AstVisitor) visitIntegerLiteral(caller *IAstVisitor, exp *IntegerLiteral) int {
	return exp.value
}

func (selfx AstVisitor) visitDecimalLiteral(caller *IAstVisitor, exp *DecimalLiteral) float64 {
	return exp.value
}

func (selfx AstVisitor) visitStringLiteral(caller *IAstVisitor, exp *StringLiteral) string {
	return exp.value
}

func (selfx AstVisitor) visitNullLiteral(caller *IAstVisitor, exp *NullLiteral) interface{} {
	return nil
}

func (selfx AstVisitor) visitBooleanLiteral(caller *IAstVisitor, exp *BooleanLiteral) bool {
	return exp.value
}

func (selfx AstVisitor) visitVariable(caller *IAstVisitor, variable *Variable) interface{} {
	return nil
}

//执行1次函数调用
//这里要看子类如何继承
func (selfx AstVisitor) visitFunctionCall(caller *IAstVisitor, functionCall *FunctionCall) interface{} {
	return nil
}
